// Fill out your copyright notice in the Description page of Project Settings.

#include "WinstonLogger.h"

// 初始化单例实例
FWinstonLogger* FWinstonLogger::SingletonInstance = nullptr;

FWinstonLogger::FWinstonLogger()
    : CurrentLogLevel(ELogLevel::Info)
    , bIsInitialized(false)
    , bEnableFileLogging(false)
    , LogFileHandle(nullptr)
{
}

FWinstonLogger::~FWinstonLogger()
{
    Shutdown();
}

FWinstonLogger& FWinstonLogger::Get()
{
    // 双重检查锁定模式实现线程安全的单例
    if (SingletonInstance == nullptr)
    {
        static FCriticalSection SingletonMutex;
        FScopeLock Lock(&SingletonMutex);
        if (SingletonInstance == nullptr)
        {
            SingletonInstance = new FWinstonLogger();
        }
    }
    return *SingletonInstance;
}

void FWinstonLogger::Initialize(const FString& LogDirectory, const FString& LogFileName, bool bEnableFileLog)
{
    FScopeLock Lock(&LogMutex);
    
    if (bIsInitialized)
    {
        UE_LOG(LogTemp, Warning, TEXT("WinstonLogger already initialized!"));
        return;
    }

    // 保存配置
    LogDir = LogDirectory;
    LogFilePrefix = LogFileName;
    bEnableFileLogging = bEnableFileLog;
    
    // 创建日志目录
    if (bEnableFileLogging)
    {
        IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
        FString FullLogDir = FPaths::ProjectDir() / LogDir;
        
        if (!PlatformFile.DirectoryExists(*FullLogDir))
        {
            if (!PlatformFile.CreateDirectory(*FullLogDir))
            {
                UE_LOG(LogTemp, Error, TEXT("Failed to create log directory: %s"), *FullLogDir);
                bEnableFileLogging = false;
            }
        }
        
        if (bEnableFileLogging)
        {
            // 创建日志文件（使用日期作为文件名的一部分）
            FString Timestamp = FDateTime::Now().ToString(TEXT("yyyy-MM-dd"));
            CurrentLogFilePath = FullLogDir / FString::Printf(TEXT("%s_%s.log"), *LogFilePrefix, *Timestamp);
            
            // 打开日志文件
            LogFileHandle = FFileManagerGeneric::Get().OpenWrite(*CurrentLogFilePath);
            if (!LogFileHandle)
            {
                UE_LOG(LogTemp, Error, TEXT("Failed to open log file: %s"), *CurrentLogFilePath);
                bEnableFileLogging = false;
            }
            else
            {
                // 写入日志文件头
                FString LogHeader = FString::Printf(
                    TEXT("========= %s Log Started at %s ========\n"), 
                    *LogFilePrefix, 
                    *FDateTime::Now().ToString()
                );
                WriteToLogFile(LogHeader);
            }
        }
    }
    
    bIsInitialized = true;
    
    // 记录初始化成功的日志
    LogInternal(ELogLevel::Info, TEXT("WinstonLogger"), TEXT("Logger initialized successfully"));
    if (bEnableFileLogging)
    {
        LogInternal(ELogLevel::Debug, TEXT("WinstonLogger"), FString::Printf(TEXT("Log file: %s"), *CurrentLogFilePath));
    }
}

void FWinstonLogger::Shutdown()
{
    FScopeLock Lock(&LogMutex);
    
    if (!bIsInitialized)
    {
        return;
    }
    
    // 记录关闭日志
    LogInternal(ELogLevel::Info, TEXT("WinstonLogger"), TEXT("Logger shutting down"));
    
    // 关闭并释放文件句柄
    if (LogFileHandle)
    {
        FString LogFooter = FString::Printf(
            TEXT("========= %s Log Ended at %s ========\n"), 
            *LogFilePrefix, 
            *FDateTime::Now().ToString()
        );
        WriteToLogFile(LogFooter);
        
        FFileManagerGeneric::Get().Close(LogFileHandle);
        LogFileHandle = nullptr;
    }
    
    bIsInitialized = false;
}

void FWinstonLogger::SetLogLevel(ELogLevel Level)
{
    FScopeLock Lock(&LogMutex);
    CurrentLogLevel = Level;
    LogInternal(ELogLevel::Debug, TEXT("WinstonLogger"), FString::Printf(TEXT("Log level set to: %s"), *LevelToString(Level)));
}

void FWinstonLogger::LogInternal(ELogLevel Level, const FString& Category, const FString& Message)
{
    // 获取时间戳
    FString Timestamp = GetCurrentTimestamp();
    
    // 构建日志条目
    FString LogLevelStr = LevelToString(Level);
    FString LogEntry = FString::Printf(
        TEXT("[%s] [%s] [%s]: %s"), 
        *Timestamp, 
        *LogLevelStr, 
        *Category, 
        *Message
    );
    
    // 根据日志级别使用不同的UE_LOG通道
    switch (Level)
    {
    case ELogLevel::Debug:
        UE_LOG(LogTemp, Log, TEXT("%s"), *LogEntry);
        break;
    case ELogLevel::Info:
        UE_LOG(LogTemp, Display, TEXT("%s"), *LogEntry);
        break;
    case ELogLevel::Warning:
        UE_LOG(LogTemp, Warning, TEXT("%s"), *LogEntry);
        break;
    case ELogLevel::Error:
        UE_LOG(LogTemp, Error, TEXT("%s"), *LogEntry);
        break;
    case ELogLevel::Critical:
        UE_LOG(LogTemp, Fatal, TEXT("%s"), *LogEntry);
        break;
    default:
        UE_LOG(LogTemp, Warning, TEXT("%s"), *LogEntry);
        break;
    }
    
    // 写入日志文件
    if (bEnableFileLogging && LogFileHandle)
    {
        WriteToLogFile(LogEntry + TEXT("\n"));
    }
}

FString FWinstonLogger::LevelToString(ELogLevel Level)
{
    switch (Level)
    {
    case ELogLevel::Debug:
        return TEXT("DEBUG");
    case ELogLevel::Info:
        return TEXT("INFO");
    case ELogLevel::Warning:
        return TEXT("WARNING");
    case ELogLevel::Error:
        return TEXT("ERROR");
    case ELogLevel::Critical:
        return TEXT("CRITICAL");
    default:
        return TEXT("UNKNOWN");
    }
}

FString FWinstonLogger::GetCurrentTimestamp()
{
    return FDateTime::Now().ToString(TEXT("yyyy-MM-dd HH:mm:ss.fff"));
}

void FWinstonLogger::WriteToLogFile(const FString& LogEntry)
{
    if (!LogFileHandle)
    {
        return;
    }
    
    // 将FString转换为UTF-8并写入文件
    FTCHARToUTF8 Converter(*LogEntry);
    int32 Length = Converter.Length();
    int32 BytesWritten = LogFileHandle->Write(Converter.Get(), Length);
    
    if (BytesWritten != Length)
    {
        UE_LOG(LogTemp, Error, TEXT("Failed to write to log file. Expected %d bytes, wrote %d bytes."), Length, BytesWritten);
    }
    
    // 刷新缓冲区确保日志立即写入
    LogFileHandle->Flush();
}